#include "parseNode.h"

parseNode::parseNode(std::string& nKey, int* nFinalState, SmartPointer<tNode>& nNode)
{
	ci = 0;
	finalState = nFinalState;
	iState = nNode;
	open.insert(std::pair<std::string, SmartPointer<tNode>>(nKey, nNode));
}

void	parseNode::launchAStar()
{
	bool							end = false;
	std::list<SmartPointer<tNode>>	lstNode;
	SmartPointer<tNode>				currentNode = iState;

	end = checkEnd(currentNode);
	while (end != true)
	{
		currentNode.getPointer()->makeSuiteNode(lstNode, currentNode);
		fusionLst(lstNode, currentNode);
		if (lstNode.empty() == false && currentNode.getPointer()->getKey() != lstNode.front().getPointer()->getKey())
		{		
			currentNode = lstNode.front();
			end = checkEnd(currentNode);
		}
		else if (open.empty() == false)
			currentNode = open.begin()->second;
		else
		{
			currentNode = SmartPointer<tNode>();
			end = true;
		}
		lstNode.clear();
	}	
	showResult(currentNode);
}


void	parseNode::fusionLst(std::list<SmartPointer<tNode>>& lst, SmartPointer<tNode> currentNode)
{
	std::list<SmartPointer<tNode>>::iterator				it;
	std::map<std::string, SmartPointer<tNode>>::iterator	itMap;

	if ((itMap = open.find(currentNode.getPointer()->getKey())) != open.end())
	{
		ci++;
		close.insert(std::pair<std::string, SmartPointer<tNode>>(itMap->first, itMap->second));
		open.erase(itMap);
		it = lst.begin();
		while ( it != lst.end() )
		{
			itMap = close.find(it->getPointer()->getKey());
			if (itMap == close.end())
			{
				itMap = open.find(it->getPointer()->getKey());
				if (itMap == open.end())
				{
					it->getPointer()->launchCalc(finalState);
					open.insert(std::pair<std::string, SmartPointer<tNode>>(it->getPointer()->getKey(), (*it)));
				}
				else if (itMap->second.getPointer()->getTotalCout() > it->getPointer()->getTotalCout())
				{
					itMap->second.getPointer()->setTotalCout(it->getPointer()->getTotalCout());
					itMap->second.getPointer()->setFather(it->getPointer()->getFather());
					it->getPointer()->setH(itMap->second.getPointer()->getH() - itMap->second.getPointer()->getTotalCout() + it->getPointer()->getTotalCout());
					itMap->second.getPointer()->setH(it->getPointer()->getH());
				}
				else
					(*it) = itMap->second;
				it++;
			}
			else if (itMap->second.getPointer()->getTotalCout() > it->getPointer()->getTotalCout())
			{
				itMap->second.getPointer()->setTotalCout(it->getPointer()->getTotalCout());
				itMap->second.getPointer()->setFather(it->getPointer()->getFather());
				it->getPointer()->setH((itMap->second.getPointer()->getH() - itMap->second.getPointer()->getTotalCout() + it->getPointer()->getTotalCout()));
				itMap->second.getPointer()->setH(it->getPointer()->getH());
				open.insert(std::pair<std::string, SmartPointer<tNode>>(itMap->first, itMap->second));
				close.erase(itMap);
				it++;
			}
			else
				it = lst.erase(it);
		}
		if (lst.empty() != true)
			lst.sort(sortList);
	}
}

bool	sortList(SmartPointer<tNode>& left, SmartPointer<tNode>& right)
{
	if (left.getPointer()->getH() < right.getPointer()->getH())
		return true;
	return false;
}

bool	parseNode::checkEnd(SmartPointer<tNode> node)
{
	if (open.empty() == true || node.getPointer() == NULL)
		return true;
	else
	{
		int*	state = node.getPointer()->getState().getPointer();
		int		len = node.getPointer()->getLenTab();
		int		stop = len * len;
		int		count;

		for (count = 0; count < stop; count++)
			if (state[count] != finalState[count])
				return false;
		return true;
	}
}

void	parseNode::showResult(SmartPointer<tNode>& node)
{
	std::list<SmartPointer<int>>	lst;
	std::list<SmartPointer<int>>::iterator	it;
	int					count;

	std::cout << "Complexity in time : " << ci << std::endl;
	std::cout << "Complexity in memory : " << (open.size() + close.size()) << std::endl;
	if (node.getPointer())
	{
		int stop = node.getPointer()->getLenTab() * node.getPointer()->getLenTab();
		
		std::cout << "Number of actions : " << node.getPointer()->getTotalCout() << std::endl;
		std::cout << "Sequence : " << std::endl;
		while (node.getPointer())
		{
			lst.push_front(node.getPointer()->getState());
			node = node.getPointer()->getFather();
		}
		for (it = lst.begin(); it != lst.end(); it++)
		{
			std::cout << "{";
			for (count = 0; count < stop; count++)
			{
				std::cout << it->getPointer()[count];
				if (count != (stop - 1))
					std::cout << ", ";
			}
			std::cout << "}" << std::endl;
		}
	}
	else
		std::cout << "No solution" << std::endl;
}
